﻿// $Id: Validatable.cs 10 2008-02-29 15:58:02Z mcartoixa $

/* ***************************************************************************
 *                                                                           *
 * Copyright © 2007 NourY Solutions                                          *
 *                                                                           *
 * This file is part of DataRules.                                           *
 *                                                                           *
 * DataRules is free software; you can redistribute it and/or modify it      *
 * under the terms of the GNU Lesser General Public License as published     *
 * by the Free Software Foundation; either version 3 of the License, or      *
 * (at your option) any later version.                                       *
 *                                                                           *
 * DataRules is distributed in the hope that it will be useful, but          *
 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU          *
 * Lesser General Public License for more details.                           *
 *                                                                           *
 * You should have received a copy of the GNU Lesser General Public          *
 * License along with this program.  If not, see                             *
 * <http://www.gnu.org/licenses/lgpl.html>.                                  *
 *                                                                           *
 *************************************************************************** */

/*! \file
 * \brief Definition of \c Salamanca.DataRules.IValidatable.
 *
 * \author $Author: mcartoixa $
 * \date $Date: 2008-02-29 16:58:02 +0100 (ven., 29 févr. 2008) $
 * \version $Revision: 10 $
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace Salamanca.DataRules
{



    ///////////////////////////////////////////////////////////////////////////
    ///
    /// <summary>Defines the arguments for a validation event.</summary>
    ///
    ///////////////////////////////////////////////////////////////////////////

    public sealed class ValidationEventArgs:
        EventArgs
    {

        /// <summary>Initializes a new instance of the <see cref="ValidationEventArgs"/> class.</summary>
        public ValidationEventArgs()
        {
        }

        /// <summary>Initializes a new instance of the <see cref="ValidationEventArgs"/> class.</summary>
        /// <param name="propertyName">The name of the property being validated.</param>
        public ValidationEventArgs(string propertyName)
        {
            _PropertyName=propertyName;
        }

        /// <summary>Gets the name of the property being validated.</summary>
        /// <value>The name of the property being validated.</value>
        public string PropertyName
        {
            get
            {
                return _PropertyName;
            }
        }

        /// <summary>The name of the property being validated.</summary>
        private string _PropertyName;
    }



    ///////////////////////////////////////////////////////////////////////////
    ///
    /// <summary>Interface implemented by a validatable object.</summary>
    /// <example>
    ///   <code>
    /// public class Validatable:
    ///     IValidatable
    /// {
    ///     public Validatable()
    ///     {
    ///     }
    ///
    ///     public bool Validate()
    ///     {
    ///         return Validate(null);
    ///     }
    ///
    ///     public bool Validate(string propertyName)
    ///     {
    ///         OnValidating(new ValidationEventArgs(propertyName));
    ///
    ///         return Salamanca.DataRules.Rules.Validate(this, propertyName, Rules);
    ///     }
    ///
    ///     protected virtual IList&lt;IRule&gt; CreateRules()
    ///     {
    ///         return Salamanca.DataRules.Rules.CreateRules(GetType());
    ///     }
    ///
    ///     protected virtual void OnValidating(ValidationEventArgs e)
    ///     {
    ///         if (Validating!=null)
    ///             Validating(this, e);
    ///     }
    ///
    ///     private ReadOnlyCollection&lt;IRule&gt; GetBrokenRules()
    ///     {
    ///         OnValidating(new ValidationEventArgs());
    ///
    ///         return GetBrokenRules(null);
    ///     }
    ///
    ///     private ReadOnlyCollection&lt;IRule&gt; GetBrokenRules(string propertyName)
    ///     {
    ///         OnValidating(new ValidationEventArgs(propertyName));
    ///
    ///         return Salamanca.DataRules.Rules.GetBrokenRules(this, propertyName, Rules);
    ///     }
    ///
    ///     private List&lt;IRule&gt; Rules
    ///     {
    ///         get
    ///         {
    ///             ///  Get the list of intrinsic rules
    ///             if (_Rules==null)
    ///             {
    ///                 List&lt;IRule&gt; tmp=new List&lt;IRule&gt;(CreateRules());
    ///
    ///                 ///  Validate ... the rules !
    ///                 foreach (IRule r in tmp)
    ///                 {
    ///                     ///  The property name must be valid for this type
    ///                     bool check=
    ///                         (r.PropertyName.Length==0)||
    ///                         (GetType().GetProperty(r.PropertyName, BindingFlags.Instance|BindingFlags.Public|BindingFlags.FlattenHierarchy)!=null);
    ///                     Debug.Assert(check);
    ///                     if (!check)
    ///                         throw new InvalidOperationException();
    ///                 }
    ///
    ///                 _Rules=tmp;
    ///             }
    ///
    ///             return _Rules;
    ///         }
    ///     }
    ///
    ///     public event EventHandler&lt;ValidationEventArgs&gt; Validating;
    ///
    ///     #region IValidatable
    ///     bool IValidatable.Validate(string propertyName)
    ///     {
    ///         return Validate(propertyName);
    ///     }
    ///
    ///     IList&lt;IRule&gt; IValidatable.GetBrokenRules()
    ///     {
    ///         return GetBrokenRules();
    ///     }
    ///
    ///     IList&lt;IRule&gt; IValidatable.GetBrokenRules(string propertyName)
    ///     {
    ///         return GetBrokenRules(propertyName);
    ///     }
    ///
    ///     IList&lt;IRule&gt; IValidatable.Rules
    ///     {
    ///         get
    ///         {
    ///             return Rules;
    ///         }
    ///     }
    ///     #endregion
    ///
    ///     private List&lt;IRule&gt; _Rules;
    ///
    /// }
    ///   </code>
    /// </example>
    ///
    ///////////////////////////////////////////////////////////////////////////

    public interface IValidatable
    {

        /// <summary>Validates the instance against its internal list of <see cref="Rules" />.</summary>
        /// <returns><c>true</c> if the instance is valid.</returns>
        bool Validate();

        /// <summary>Validates the instance property against the instance internal list of <see cref="Rules" />.</summary>
        /// <returns><c>true</c> if the instance is valid.</returns>
        bool Validate(string propertyName);

        /// <summary>Gets the complete list of broken rules of the current instance.</summary>
        /// <returns>The list of broken rules for this instance.</returns>
        IList<IRule> GetBrokenRules();

        /// <summary>Gets the list of broken rules concerning the specified property of the current instance.</summary>
        /// <returns>The list of broken rules concerning the specified property for this instance.</returns>
        IList<IRule> GetBrokenRules(string propertyName);

        /// <summary>Gets the list of rules that are used to <see cref="Validate()" /> the instance.</summary>
        IList<IRule> Rules
        {
            get;
        }

        /// <summary>Raised when the instance is validated.</summary>
        event EventHandler<ValidationEventArgs> Validating;
    }



    ///////////////////////////////////////////////////////////////////////////
    ///
    /// <summary>Interface implemented by an extensible validatable object.</summary>
    ///
    ///////////////////////////////////////////////////////////////////////////

    public interface IValidationExtensible:
        IValidatable
    {

        /// <summary>Registers the specified extender on the current instance.</summary>
        /// <param name="provider">The validation extender provider.</param>
        /// <returns><c>true</c> if the extender provider was succesfully registered.</returns>
        bool RegisterExtender(IValidationExtenderProvider provider);

        /// <summary>Unregisters the specified extender on the current instance.</summary>
        /// <param name="provider">The validation extender provider.</param>
        void UnregisterExtender(IValidationExtenderProvider provider);

    }



    ///////////////////////////////////////////////////////////////////////////
    ///
    /// <summary>Interface implemented by a validation extender provider.</summary>
    ///
    ///////////////////////////////////////////////////////////////////////////

    public interface IValidationExtenderProvider
    {

        /// <summary>Gets the extended rules corresponding to the specified target.</summary>
        /// <param name="extendee">The extended instance.</param>
        /// <returns>The list of extended rules.</returns>
        IList<IRule> GetExtendedRules(IValidationExtensible extendee);
    }

}
